﻿using Microsoft.Extensions.Configuration;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace SD.App.Desktop.Utils
{
    /// <summary>
    /// 加密解密工具类（AES 可逆算法，用于非密码敏感信息）
    /// </summary>
    public class EncryptionHelper : ISingletonLifetime
    {
        private readonly IConfiguration _configuration;
        private readonly ILogger _logger;

        /// <summary>
        /// 密钥（16/24/32 字节，对应 AES-128/AES-192/AES-256）
        /// 生产环境建议从配置文件读取，且定期更换
        /// </summary>
        private readonly string _aesKey = "Avalonia_AES_Key_2025"; // 16 字节（AES-128）
        /// <summary>
        /// 初始化向量（16 字节，必须与密钥长度匹配）
        /// </summary>
        private readonly string _aesIv = "Avalonia_AES_IV_2025"; // 16 字节
        /// <summary>
        /// 盐值（用于密码加密，生产环境建议配置在 appsettings.json 中）
        /// </summary>
        private readonly string _passwordSalt = "Avalonia_PgSQL_App_2025_Production"; // 不再硬编码

        public EncryptionHelper(IConfiguration configuration,
            ILogger logger)
        {
            _configuration = configuration;
            _logger = logger;

            // 从配置文件读取盐值（若配置缺失，使用默认值兜底）
            _passwordSalt = configuration["AppSettings:PasswordSalt"] ?? "Avalonia_Default_Salt_2025";

            _logger.Debug("用户名密码加密盐值来源：{SaltSource}",
                string.IsNullOrEmpty(configuration["AppSettings:PasswordSalt"]) ? "默认值" : "配置文件");

            // 从 appsettings.json 读取配置，缺失则抛异常（生产环境必须配置）
            _aesKey = configuration["Encryption:AesKey"]
                ?? throw new ArgumentNullException("Encryption:AesKey", "AES 密钥未在配置文件中配置");
            _aesIv = configuration["Encryption:AesIv"]
                ?? throw new ArgumentNullException("Encryption:AesIv", "AES 初始化向量未在配置文件中配置");

            // 校验密钥长度（AES 要求）
            ValidateAesConfig();
        }

    
        /// <summary>
        /// AES 加密（可逆）
        /// </summary>
        /// <param name="plainText">明文</param>
        /// <returns>加密后的 Base64 字符串</returns>
        public string AesEncrypt(string plainText)
        {
            if (string.IsNullOrEmpty(plainText))
                throw new ArgumentNullException(nameof(plainText), "明文不能为空");

            using var aes = Aes.Create();
            aes.Key = Encoding.UTF8.GetBytes(_aesKey);
            aes.IV = Encoding.UTF8.GetBytes(_aesIv);
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;

            // 加密流
            using var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
            using var memoryStream = new MemoryStream();
            using var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);

            // 写入明文并加密
            byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
            cryptoStream.Write(plainBytes, 0, plainBytes.Length);
            cryptoStream.FlushFinalBlock();

            // 转换为 Base64 字符串（便于存储和传输）
            return Convert.ToBase64String(memoryStream.ToArray());
        }

        /// <summary>
        /// AES 解密（可逆）
        /// </summary>
        /// <param name="encryptedText">AesEncrypt 加密后的 Base64 字符串</param>
        /// <returns>解密后的明文</returns>
        public string AesDecrypt(string encryptedText)
        {
            if (string.IsNullOrEmpty(encryptedText))
                throw new ArgumentNullException(nameof(encryptedText), "密文不能为空");

            using var aes = Aes.Create();
            aes.Key = Encoding.UTF8.GetBytes(_aesKey);
            aes.IV = Encoding.UTF8.GetBytes(_aesIv);
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;

            // 解密流
            using var decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
            using var memoryStream = new MemoryStream(Convert.FromBase64String(encryptedText));
            using var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);

            // 读取解密后的明文
            using var streamReader = new StreamReader(cryptoStream, Encoding.UTF8);
            return streamReader.ReadToEnd();
        }

        #region 密码加密与验证（SHA256 + 盐值）
        public string EncryptPassword(string plainPassword)
        {
            // 盐值 + 明文密码拼接
            string saltedPassword = $"{_passwordSalt}_{plainPassword}";

            // SHA256 加密
            using var sha256 = SHA256.Create();
            byte[] bytes = Encoding.UTF8.GetBytes(saltedPassword);
            byte[] hashBytes = sha256.ComputeHash(bytes);

            // 转换为 16 进制字符串（数据库存储）
            StringBuilder sb = new();
            foreach (byte b in hashBytes)
            {
                sb.Append(b.ToString("x2")); // 小写 16 进制
            }
            return sb.ToString();
        }

        public bool VerifyPassword(string plainPassword, string encryptedPassword)
        {
            // 明文密码加密后与数据库密码对比
            string encryptedPlainPassword = EncryptPassword(plainPassword);
            return string.Equals(encryptedPlainPassword, encryptedPassword, StringComparison.OrdinalIgnoreCase);
        }
        #endregion

        /// <summary>
        /// 校验 AES 密钥和向量长度合法性
        /// </summary>
        private void ValidateAesConfig()
        {
            byte[] keyBytes = Encoding.UTF8.GetBytes(_aesKey);
            byte[] ivBytes = Encoding.UTF8.GetBytes(_aesIv);

            // 密钥长度必须是 16、24 或 32 字节（对应 AES-128、AES-192、AES-256）
            if (!new[] { 16, 24, 32 }.Contains(keyBytes.Length))
            {
                throw new InvalidOperationException($"AES 密钥长度必须是 16、24 或 32 字节，当前长度：{keyBytes.Length} 字节");
            }

            // 初始化向量必须是 16 字节（AES 标准）
            if (ivBytes.Length != 16)
            {
                throw new InvalidOperationException($"AES 初始化向量必须是 16 字节，当前长度：{ivBytes.Length} 字节");
            }
        }
    }
}
